using System;
using System.IO;
using System.Text;

namespace ThalesHsmComms
{
	public class ExportDESKeyMsg : WSMMsg
	{

		private readonly String ENCRYPTION_ALGORITHM_RSA = "01";
		private readonly String PAD_MODE_PKCS = "01"; 
		private readonly String DES_KEY_TYPE_BDK = "2800";
		
		private String publicKeyExponent;
		private String publicKeyModulus;
		private String publicKeyMac;
		
		private String encryptionIdentifier;
		private String padModeIdentifier;
		private String desKeyType;
		private String desKeyFlag;
		private String desKeyLmk;
		private String desKeyCheckValue;
		
		private String desKeyInitValue;
		private String desKeyPublicKey;

		public ExportDESKeyMsg (String des_key_lmk, String des_key_check_value, String public_key_modulus, String public_key_exponent, String public_key_mac)
			:base("GK")
		{
			
			this.publicKeyExponent = public_key_exponent;
			this.publicKeyModulus = public_key_modulus;
			this.publicKeyMac = public_key_mac;
			
			this.desKeyLmk = "" + des_key_lmk;
			this.desKeyCheckValue = des_key_check_value;
			
			this.desKeyType = DES_KEY_TYPE_BDK;
			this.padModeIdentifier = PAD_MODE_PKCS;
			this.encryptionIdentifier = ENCRYPTION_ALGORITHM_RSA;
			
			this.desKeyFlag = "1";

		}

		override protected void Encode() 
		{
			
			StringBuilder data = new StringBuilder();
			MemoryStream ms = new MemoryStream();
			
			try 
			{		
				// pack command code
				data.Append(this.commandCode);
				
				// pack encryption identifier
				data.Append(this.encryptionIdentifier);
				
				// pack pad mode identifier
				data.Append(this.padModeIdentifier);
				
				// pack des key type
				data.Append(this.desKeyType);
				
				// pack des key flag
				data.Append(this.desKeyFlag);
				
				// pack des key
				data.Append(this.desKeyLmk);
				
				// pack des check digit
				data.Append(this.desKeyCheckValue);

				byte[] tmp = ASCIIEncoding.ASCII.GetBytes(data.ToString());
				ms.Write(tmp,0,tmp.Length);

				// pack public key mac
				//data.Append(HexConverter.fromHex2ByteArray(public_key_mac.getBytes()));
				tmp = HexConverter.FromHex2Binary(this.publicKeyMac);
				ms.Write(tmp,0,tmp.Length);


				// pack public key
				// pack module in byte stream
				MemoryStream modulusStream = new MemoryStream();
				modulusStream.WriteByte(0x02);	// integer
				int modLen = this.publicKeyModulus.Length / 2;
				if (modLen > 0x7F) {
					modulusStream.WriteByte(0x81);
					modulusStream.WriteByte((byte) modLen);
				}
				else
					modulusStream.WriteByte((byte) modLen);


				tmp = HexConverter.FromHex2Binary(this.publicKeyModulus);
				modulusStream.Write(tmp,0,tmp.Length);
				
				
				// pack exponent
				MemoryStream exponentStream = new MemoryStream();
				exponentStream.WriteByte(0x02);	// integer
				int expLen = this.publicKeyExponent.Length / 2;
				
				if (expLen > 0x7F) {
					exponentStream.WriteByte(0x81);
					exponentStream.WriteByte((byte) expLen);
				}
				else
					exponentStream.WriteByte((byte) expLen);


				tmp = HexConverter.FromHex2Binary(this.publicKeyExponent);
				exponentStream.Write(tmp,0,tmp.Length);
				
				
				// put it all together
				ms.WriteByte(0x30);	// start of sequence
				int modExpLen = (int)(modulusStream.Length + exponentStream.Length);
				if (modExpLen > 0x7F) {
					ms.WriteByte(0x81);
					ms.WriteByte((byte) modExpLen);
				}
				else
					ms.WriteByte((byte) modExpLen);

				tmp = modulusStream.ToArray();
				ms.Write(tmp,0,tmp.Length);
				tmp = exponentStream.ToArray();
				ms.Write(tmp,0,tmp.Length);
				
				this.requestData = ms.ToArray();
				
			} catch (IOException ex) 
			{
				Console.WriteLine(ex);
			}
		}

		override protected void Decode()
		{
			// get des key init value
			this.desKeyInitValue = this.GetNextBytesFromResponse(16);
			int len = int.Parse(this.GetNextBytesFromResponse(4));
			
			this.desKeyPublicKey = HexConverter.FromBinary2HexString(Encoding.ASCII.GetBytes(this.GetNextBytesFromResponse(len)));
		}

	}
}

